<?php
/********************************************************************
 *	Author:
 *		Jestery Liu <jestery@gmail.com>
 *		http://www.pte.cn
 *
 *	File:			http_response.class.php
 *	Create Date:	2007-05-18 15:30:16 CST
 *******************************************************************/

require_once(PTE::getCoreLibsPath().'Response.interface.php');
require_once(PTE::getCoreLibsPath().'Event.class.php');

class HttpResponse implements IResponse
{
	private $httpResponseCode = 200;
	private $headers = array();
	private $body = array();
	private $obEnabled = true;
	private $obHandler = null;
	
	public function __construct($outputBuffing = true, $obHandler = 'ob_gzhandler')
	{
		$this->obEnabled = $outputBuffing;
		$this->obHandler = $obHandler;
		if ($this->obEnabled)
		{
			@ob_end_clean();
			ob_start($this->obHandler);
		}
	}
	
	public function obEnabled()
	{
		return $this->obEnabled;
	}

	public function setHttpResponseCode($code)
	{
		Event::notifyEvent($this, 'preSetHttpResponseCode', array('code'=>&$code));
		if (!is_int($code) || (100 > $code) || (599 < $code))
		{
			trigger_error('Invalid http_response_code.', E_USER_ERROR);
		}
		$this->httpResponseCode = $code;
		Event::notifyEvent($this, 'postSetHttpResponseCode', array('code'=>&$code));
	}
	public function getHttpResponseCode()
	{
		return $this->httpResponseCode;
	}
	public function addHeader($headerName, $value, $replace=false)
	{
		Event::notifyEvent($this, 'preAddHeader',
							array('headerName'=>&$headerName, 'value'=>&$value, 'replace'=>&$replace));
		$this->addRawHeader($headerName.': '.$value, $replace);
	}
	public function addRawHeader($header, $replace=false)
	{
		Event::notifyEvent($this, 'preAddRawHeader',
							array('header'=>&$header, 'replace'=>&$replace));
		array_push($this->headers, array('value'=>$header, 'replace'=>$replace));
	}
	public function addNoCacheHeaders()
	{
		$this->addRawHeader("Expires: Mon, 26 Jul 1997 05:00:00 GMT", true);
		$this->addRawHeader("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT", true);
		$this->addRawHeader("Cache-Control: no-store, no-cache, must-revalidate", true);
		$this->addRawHeader("Cache-Control: post-check=0, pre-check=0", false);
		$this->addRawHeader("Pragma: no-cache", true);
	}
	public function clearHeaders()
	{
		Event::notifyEvent($this, 'preClearHeaders', array('headers'=>&$this->headers));
		$this->headers = array();
		Event::notifyEvent($this, 'postClearHeaders', array());
	}
	public function getHeaders()
	{
		return $this->headers;
	}
	public function canSendHeaders()
	{
		$bool = headers_sent($file, $line);
		if ($bool)
		{
			throw new Exception("Headers already sent in $file on line $line.");
		}
		return !$bool;
	}
	public function sendHeaders()
	{
		Event::notifyEvent($this, 'preSendHeaders', array('headers'=>&$this->headers));
		if (count($this->headers)<0)
		{
			return true;
		}
		$this->canSendHeaders();
		$firstHeader = array_shift($this->headers);
		header($firstHeader['value'], true, $this->httpResponseCode);
		foreach ($this->headers as $header)
		{
			header($header['value'], $header['replace']);
		}
		Event::notifyEvent($this, 'postSendHeaders', array('headers'=>&$this->headers));
		$this->clearHeaders();
		return true;
	}
	public function add404Header()
	{
		Event::notifyEvent($this, 'preAdd404Header', array('headers'=>&$this->headers));
		array_unshift($this->headers, array('value'=>'Not Found', 'replace'=>true));
		$this->addHeader('Connection', 'close', true);
		$this->setHttpResponseCode(404);
	}

	public function setRedirect($url)
	{
		Event::notifyEvent($this, 'preSetRedirect', array('url'=>&$url));
		$this->addRawHeader("Location: $url", true);
		$this->setHttpResponseCode(302);
	}

	public function setCookie($name, $value, $life = 0)
	{
		Event::notifyEvent($this, 'preSetCookie',
							array('name'=>&$name, 'value'=>&$value, 'life'=>&$life));
		$config = Instances::get('config');
		$cookiedomain = $config->get('COOKIE_DOMAIN');
		$cookiepath = $config->get('COOKIE_PATH');
		$timestamp = time();
		setcookie($config->get('COOKIE_PREFIX').$name, $value,
		$life ? $timestamp + $life : 0, $cookiepath,
		$cookiedomain, $_SERVER['SERVER_PORT'] == 443 ? 1 : 0);
		Event::notifyEvent($this, 'postSetCookie',
							array('name'=>&$name, 'value'=>&$value, 'life'=>&$life));
	}
	
	public function addBodyContent($content, $name='default')
	{
		Event::notifyEvent($this, 'preAddBodyContent', array('content'=>&$content, 'name'=>&$name));
		$this->body[$name] = (string)$content;
		Event::notifyEvent($this, 'postAddBodyContent', array('content'=>&$content, 'name'=>&$name));
	}
	public function appendBodyContentToSegment($content, $name='default')
	{
		Event::notifyEvent($this, 'preAppendBodyContentToSegment', array('content'=>&$content, 'name'=>&$name));
		$this->body[$name].=(string)$content;
		Event::notifyEvent($this, 'postAppendBodyContentToSegment', array('content'=>&$content, 'name'=>&$name));
	}
	public function prependBodyContentToSegment($content, $name='default')
	{
		Event::notifyEvent($this, 'prePrependBodyContentToSegment', array('content'=>&$content, 'name'=>&$name));
		$this->body[$name] = (string)$content.$this->body[$name];
		Event::notifyEvent($this, 'postPrependBodyContentToSegment', array('content'=>&$content, 'name'=>&$name));
	}
	public function insertBodyContent($content, $name, $segName=null, $before=false)
	{
		Event::notifyEvent($this, 'preInsertBodyContent',
		array('content'=>&$content, 'name'=>&$name, 'segName'=>&$segName, 'before'=>&$before));
		if ($segName===null || !isset($this->body[$segName]))
		{
			$this->addBodyContent($content, $name);
		}
		$keys = array_keys($this->body);
		$pos = array_search($segName, $keys)+1;
		if ($before)
		{
			$pos--;
		}
		array_splice($this->body, $pos, 0, array('name'=>$content));
		Event::notifyEvent($this, 'postInsertBodyContent',
		array('content'=>&$content, 'name'=>&$name, 'segName'=>&$segName, 'before'=>&$before));
	}
	public function sendBody()
	{
		Event::notifyEvent($this, 'preSendBody', array('body'=>&$this->body));
		foreach ($this->body as $content)
		{
			echo $content;
		}
		Event::notifyEvent($this, 'postSendBody', array('body'=>&$this->body));
		$this->clearBody();
	}
	public function clearBody($name=null)
	{
		Event::notifyEvent($this, 'preClearBody', array('name'=>&$name));
		if ($name===null)
		{
			$this->body = array();
		}
		else
		{
			unset($this->body[$name]);
		}
		Event::notifyEvent($this, 'postClearBody', array('name'=>&$name));
	}
	public function getBody()
	{
		return $this->body();
	}
	public function send($flush=true)
	{
		Event::notifyEvent($this, 'preSend', array('flush'=>&$flush, 'body'=>&$this->body));
		$this->sendHeaders();
		$this->sendBody();
		if ($flush)
		{
			@ob_end_flush();
		}
		Event::notifyEvent($this, 'postSend', array('flush'=>&$flush));
	}
	public function __toString()
	{
		@ob_start();
		$this->send(false);
		return ob_get_clean();
	}
}

/* vim: set ts=4 sw=4 ff=unix: */
